package com.hugang.classicalcase;

/**
 * 经典例题：生产者和消费者问题
 * <p>
 * 生产者(Productor)将产品交给店员(Clerk)，而消费者(Customer)从店员处 取走产品，
 * 店员一次只能持有固定数量的产品(比如:20），如果生产者试图 生产更多的产品，店员会叫
 * 生产者停一下，如果店中有空位放产品了再通 知生产者继续生产；如果店中没有产品了，店
 * 员会告诉消费者等一下，如 果店中有产品了再通知消费者来取走产品
 * <p>
 * 分析：
 * 1、是否有多个线程？有，生产者线程和消费者线程
 * 2、是否有共享数据？有，店员（或产品）
 * 3、如何解决线程安全问题？三种方式，同步代码块，同步方法，Lock
 * 4、是否涉及线程通信？是
 *
 * @author hg
 * @date 2020/6/16 16:03
 */
public class Test {

    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Thread producer = new Productor(clerk);
        producer.setName("生产者线程1");
        Thread customer1 = new Consumer(clerk);
        customer1.setName("消费者线程1");
        Thread customer2 = new Consumer(clerk);
        customer2.setName("消费者线程2");

        producer.start();
        customer1.start();
        customer2.start();

    }
}


class Clerk {

    private int product = 0;

    public int getProduct() {
        return product;
    }

    public void setProduct(int product) {
        this.product = product;
    }

    public synchronized void produccProduct() {
        if (product <= 20) {
            product++;
            System.out.println(Thread.currentThread().getName() + ":生产了一个产品，当前产品数量为：" + product);
            notify();
        } else {
            try {
                System.out.println("当前产品数量为20，" + Thread.currentThread().getName() + "等待");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void consumeProduct() {
        if (product > 0) {
            product--;
            System.out.println(Thread.currentThread().getName() + ":消费了一个产品，当前产品数量为：" + product);
            notify();
        } else {
            try {
                System.out.println("当前产品数量为0，" + Thread.currentThread().getName() + "等待");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Productor extends Thread {
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            clerk.produccProduct();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer extends Thread {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            clerk.consumeProduct();

            try {
                Thread.sleep(2200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
